Introduction
The National Football League (NFL) is a syndicate of 32 teams which
over the last several decades has become not only America’s favorite
past time but also one of the most profitable leagues globally. In 2023,
the league generated over 20 billion dollars in revenue and held 93
spots in the top 100 most watched broadcasts. A large part of the
success the league enjoys is due to its scarcity. The regular season is
only 18 weeks long, where each team plays 17 games along with one bye
week for rest. This is in sharp contrast to other sports leagues where
teams might play hundreds of games.
Although the NFL season is short, there is an abundance of data
generated each game and over the span of a season. Finding ways to
leverage this data is important to the success and health of a team and
its players. More recently, fantasy leagues and the growing popularity
of sports gambling have amplified the significance of this data for fans
and Wall Street investors seeking profitable opportunities.
For this project, we selected a relatively simple data set
encompassing box score statistics for each NFL team during the 2023
regular season gathered from pro-football-reference (https://www.pro-football-reference.com/). Our data
consists of 544 observations and 25 features (23 predictors and 2
response) which are listed below. Our goal is simple:
- Can we use box score statistics to predict the points scored by a
team via linear regression?
- Can we use box score statistics to predict the result of the game
via logistic regression?
Team : Name of the team
Week : Week of the season
Day : Day the game was played
Date : Date the game was played
Time : Time the game was played
Result : W if the won or L if they lost
OT : If the game went into overtime
Rec : Win-loss record
isHome : Weather the team played at home or away
Opp : Opponent the team played against
Tm_score : Points scored
Opp_score : Points scored by opponent
1stD_Off : First downs gained by offense
TotYd_Off : Total yardage gained by offense
PassY_Off : Passing yardage gained by offense
RushY_Off : Rushing yardage gained by offense
TO_Off : Turnovers by the offense
1stD_Def : First downs given up by defense
TotY_Def : Total yardage given up by defense
PassY_Def : Passing yardage given up by defense
RushY_Def : Rushing yardage given up by defense
TO_Def : Turnovers caused by defense
OffenseExp : Expected points by offense
DefenseExp : Expected points by defense
SpTms_Exp : Expected points by special teams
Note: The expected points features are calculated via play
by play data. According to pro-football-reference, expected points
represent the estimated point value at the start of a given play, based
on down, distance, and field position.
EDA and Feature
Engineering
Cleaning Data and
Feature Engineering
A quick glance at our data, shows us that almost all of our columns
have missing values. We handle this in two ways:
- The 32 missing values in many of our columns occur because this data
includes the bye where no data is generated. We drop these rows.
- The other missing values are due to the way our source inputs the
data, leaving things blank when an event does not occur. For example, in
the OT column, if the game goes into overtime, OT is listed, otherwise,
the cell is left blank. Similarly, if a team does not generate a
turnover, the entry is blank. We fill these missing values in as
zero.
Team Week Day Date
Length:576 Min. : 1.0 Length:576 Length:576
Class :character 1st Qu.: 5.0 Class :character Class :character
Mode :character Median : 9.5 Mode :character Mode :character
Mean : 9.5
3rd Qu.:14.0
Max. :18.0
Time boxscore Result OT
Length:576 Length:576 Length:576 Length:576
Class :character Class :character Class :character Class :character
Mode :character Mode :character Mode :character Mode :character
Rec atHome Opp Tm_score
Length:576 Length:576 Length:576 Min. : 0.00
Class :character Class :character Class :character 1st Qu.:16.00
Mode :character Mode :character Mode :character Median :21.00
Mean :21.77
3rd Qu.:28.00
Max. :70.00
NA's :32
Opp_score X1stD_Off TotYd_Off PassY_Off
Min. : 0.00 Min. : 6.00 Min. : 58.0 Min. : -9.0
1st Qu.:16.00 1st Qu.:16.00 1st Qu.:273.0 1st Qu.:167.8
Median :21.00 Median :19.00 Median :335.0 Median :215.0
Mean :21.77 Mean :19.26 Mean :331.6 Mean :218.9
3rd Qu.:28.00 3rd Qu.:23.00 3rd Qu.:389.0 3rd Qu.:268.0
Max. :70.00 Max. :33.00 Max. :726.0 Max. :472.0
NA's :32 NA's :32 NA's :32 NA's :32
RushY_Off TO_Off X1stD_Def TotY_Def
Min. : 17.0 Min. :1.000 Min. : 6.00 Min. : 58.0
1st Qu.: 77.0 1st Qu.:1.000 1st Qu.:16.00 1st Qu.:273.0
Median :107.0 Median :2.000 Median :19.00 Median :335.0
Mean :112.7 Mean :1.877 Mean :19.26 Mean :331.6
3rd Qu.:141.0 3rd Qu.:2.000 3rd Qu.:23.00 3rd Qu.:389.0
Max. :350.0 Max. :6.000 Max. :33.00 Max. :726.0
NA's :32 NA's :185 NA's :32 NA's :32
PassY_Def RushY_Def TO_Def OffenseExp
Min. : -9.0 Min. : 17.0 Min. :1.000 Min. :-35.860
1st Qu.:167.8 1st Qu.: 77.0 1st Qu.:1.000 1st Qu.: -6.798
Median :215.0 Median :107.0 Median :2.000 Median : 1.990
Mean :218.9 Mean :112.7 Mean :1.877 Mean : 1.628
3rd Qu.:268.0 3rd Qu.:141.0 3rd Qu.:2.000 3rd Qu.: 9.895
Max. :472.0 Max. :350.0 Max. :6.000 Max. : 48.650
NA's :32 NA's :32 NA's :185 NA's :32
DefenseExp SpTms_Exp
Min. :-48.650 Min. :-12.380
1st Qu.: -9.895 1st Qu.: -2.845
Median : -1.990 Median : 0.000
Mean : -1.628 Mean : 0.000
3rd Qu.: 6.798 3rd Qu.: 2.845
Max. : 35.860 Max. : 12.380
NA's :32 NA's :32
To clean our data, we set our binary variables to be either 1 or 0.
We also create, two new binary variables.
- We use the
Time column to create a new variable called
isPrimeTime which lets us know whether or not the game was
played at night on national television.
- A
isThursday feature is created from the
Day column which lets us know if the game was played on
Thursday. Thursday night games are played on a short week which can lead
to sloppy play and increased risk of injury.
After dropping unnecessary columns and renaming other columns, we are
left with the following features: OT,atHome,
Tm_score , Opp_score, 1stD_Off,
TotYd_Off, PassY_Off, RushY_Off,
TO_Off, 1stD_Def, TotY_Def,
PassY_Def, RushY_Def, TO_Def,
OffenseExp, DefenseExp,
SpTms_Exp, isPrimeTime, and
isThursday.
Visualising
Distributions
The distribution for our continuous numerical variables for offense
and defense are shown below. The first down rate, total yardage, and
passing yards look to be normally distributed. The rushing yards have a
slight skew but nothing major catches the eye. Turnovers on the other
hand have a noticeable right skew which is to be expected.

Comparing the defensive plots vs the offensive plots shows that the
distributions are exactly the same but this is to be expected. Since two
teams play in a game, we have observations for both teams from the same
game. For example, suppose the Eagles play the Giants and gain 400 total
yards. This will show up as 400 under TotYd_Off but will
show up again in another observation of the Giants as
TotY_Def. We see in the two plots below that the offensive
stats do not correlate with the defensive stats for each
observation.

It should be expected that passing and rushing yards are correlated
with total yards which is indeed the case. Surprisingly, there is little
correlation between rush and pass yards.

To further capture relationships between our numerical variables we
create a Pearson correlation plot. We see that offensive expected points
feature is highly correlated with yardage. The same applies for
defensive expected points and yardage given up. And of course the total
yardage is dependent on rushing and passing yardage.

Relationship to
response variables
We would now like to take a closer look at the relationship between
our features and the response variables.To capture this relationship, we
create a scatter plot for each numerical variable against our response
variable. For our categorical variables, we create density plots.


Observations:
- Defensive statistics have no bearing on the points scored which is
not too surprising since defenses rarely score points.
- Special teams expected points has no correlation with points scored.
This is a bit surprising since, field goals and extra points are a
significant chunk of points scored during a normal game.
- Turnovers may have a slight correlation.
- A difference in the distribution between games that went into
overtime vs those that did not. Similarly, home vs away games have a
slight difference in distributions.
Plotting our features against our second response variable, we see
that almost all features have a difference in there distribtions for a
win vs a loss. The two turnover features look a bit odd and they may
pose problems downstream.

Linear Regression
Points are primarily scored by the offense and a small amount by the
special teams via extra points, field goals, punt and kick returns. In
rare cases, points can be scored by the defense. For this to happen, a
turnover is required. This fact helps us choose \(|.3|\) as the cutoff for selecting features
from the correlation plot. This decision is also supported by our
scatter plots.
Model One
The first model we build is a naive model to set a baseline. From our
visualization, we know that offensive expected points was the highest
correlated feature to our response variable so we choose this instead of
other offensives stats. Let \(O=\)OT,\(H\)=atHome, \(P\)=Tm_score , \(F_O\)=1stD_Off, \(Y_O\) = TotYd_Off, \(P_O\) = PassY_Off, \(R_O\) =RushY_Off, \(TO_O\) =TO_Off, \(F_D\) =1stD_Def, \(T_D\) =TotY_Def, \(P_D\) =PassY_Def, \(R_D\) = RushY_Def, \(TO_D\) =TO_Def, \(E_O\) =OffenseExp, \(E_D\) = DefenseExp, \(E_S\)SpTms_Exp, \(N\) = isPrimeTime, and \(T\) = isThursday.
Our first model: \[M1: \text{Points} =
\alpha_0 + \alpha_1E_D+ \alpha_2E_O + \alpha_3E_S + \alpha_4F_O +
\alpha_5 H + \alpha_6 TO_O + \alpha_7 TO_D + \alpha_8 O + \alpha_9 T +
\alpha_{10} N + \epsilon\]

Summarized statistics of the regression coefficients
| (Intercept) |
13.3393576 |
1.2557828 |
10.622345 |
0.0000000 |
| SpTms_Exp |
0.4601147 |
0.0584145 |
7.876726 |
0.0000000 |
| OffenseExp |
0.7110176 |
0.0300953 |
23.625539 |
0.0000000 |
| DefenseExp |
0.1865435 |
0.0215198 |
8.668459 |
0.0000000 |
| X1stD_Off |
0.1696519 |
0.0662606 |
2.560374 |
0.0107304 |
| TO_Off |
1.3859644 |
0.2171200 |
6.383402 |
0.0000000 |
| TO_Def |
1.6217397 |
0.2063290 |
7.859970 |
0.0000000 |
| atHome1 |
0.1725996 |
0.4206915 |
0.410276 |
0.6817683 |
| OT1 |
4.1180071 |
0.9824969 |
4.191369 |
0.0000325 |
| isThursday1 |
4.2122865 |
0.9246353 |
4.555619 |
0.0000065 |
| isPrimeTime1 |
-1.5391315 |
0.5751517 |
-2.676044 |
0.0076789 |
From the output of our first model, we see that playing at home had a
small effect on the outcome. Furthermore, we know from our correlation
plots, that the defensive and special teams had little relationship to
our response variable. Our second model is focused on offensive stats
and we remove the atHOME variable.
Model 2
Our second model: \[M2: \text{Points} =
\alpha_0 + \alpha_1E_O + \alpha_2F_O + \alpha_3 TO_D + \alpha_4 TO_O +
\alpha_5 O + \alpha_6 T + \alpha_7 N + \epsilon\]

Summarized statistics of the regression coefficients
| (Intercept) |
13.2627618 |
1.3295888 |
9.975085 |
0.0000000 |
| OffenseExp |
0.6353635 |
0.0314334 |
20.212975 |
0.0000000 |
| X1stD_Off |
0.1325279 |
0.0713863 |
1.856490 |
0.0639322 |
| TO_Off |
0.9979134 |
0.2306389 |
4.326735 |
0.0000181 |
| TO_Def |
2.5389342 |
0.1947000 |
13.040237 |
0.0000000 |
| isThursday1 |
4.0789361 |
1.0026368 |
4.068209 |
0.0000545 |
| OT1 |
4.0403746 |
1.0652762 |
3.792795 |
0.0001659 |
| isPrimeTime1 |
-1.5557811 |
0.6239310 |
-2.493515 |
0.0129489 |
Model Three
The next two models we build, we replace offensive expected points by
the three yardage statistics. The third model uses
TotYd_Off and fourth model will use RushY_Off
+ PassY_Off.
\[M3: \text{Points} = \alpha_0 +
\alpha_1Y_O + \alpha_2F_O + \alpha_3 TO_D + \alpha_4 TO_O + \alpha_5 O
+ \alpha_6 T + \alpha_7 N + \alpha_8 H + \epsilon\]

Model Four
In our fourth model, we use both rush and passing yards instead of
total yards. \[M4: \text{Points} = \alpha_0 +
\alpha_1R_O + \alpha_1P_O + \alpha_3F_O + \alpha_4 TO_D + \alpha_5 TO_O
+ \alpha_6 O + \alpha_7 T + \alpha_8 N + \alpha_9 H +
\epsilon\]

The respective \(R^2\) values for
our four models are:
- naiveModel = 0.772688,
- offModel = 0.7309864,
- yardModel = 0.6181533,
- typeYardage_model = 0.6183322
Our models based on expected value features perform much better than
the ones using yardage. This may be because the expected value features
are based on other information and thus are more informative.
Logistic
regression
For our logistic models, we will omit the three expected points
features because they capture the margin of points between two teams.
The first model we build includes all features aside from expected
points since our exploration showed a difference in distribution for
each feature.
Model One
In our fourth model, we use both rush and passing yards instead of
total yards. \[M1: \text{win} = \alpha_0 +
\alpha_1P + \alpha_3F_O + \alpha_4 F_D + \alpha_5 TO_D + \alpha_6 TO_O
+ \alpha_7 Y_O + \alpha_8 Y_D + \alpha_9 O + \alpha_{10} T + \alpha_{11}
N + \alpha_{12} H + \epsilon\]
Summary of the significant tests of the logistic regression
model
| (Intercept) |
3.0183789 |
1.1132013 |
2.7114402 |
0.0066992 |
| Tm_score |
0.2588536 |
0.0337682 |
7.6656022 |
0.0000000 |
| X1stD_Off |
-0.1537508 |
0.0556692 |
-2.7618654 |
0.0057472 |
| TotYd_Off |
0.0094882 |
0.0033489 |
2.8332499 |
0.0046077 |
| TO_Off |
-0.9399173 |
0.1513878 |
-6.2086741 |
0.0000000 |
| X1stD_Def |
-0.0715834 |
0.0518345 |
-1.3809988 |
0.1672793 |
| TotY_Def |
-0.0207389 |
0.0033062 |
-6.2727850 |
0.0000000 |
| TO_Def |
0.7652793 |
0.1590230 |
4.8123814 |
0.0000015 |
| atHome1 |
-0.2030294 |
0.2935336 |
-0.6916734 |
0.4891425 |
| isThursday1 |
-0.3598061 |
0.6806176 |
-0.5286464 |
0.5970507 |
| isPrimeTime1 |
0.0162286 |
0.4045573 |
0.0401145 |
0.9680019 |
| OT1 |
-0.7039025 |
0.5495380 |
-1.2808988 |
0.2002292 |
From the above output, we can see that our binary variables and first
downs given up by the defense have little impact and are not
significant. So in our second model, we remove them.
Model Two
\[M1: \text{win} = \alpha_0 + \alpha_1P +
\alpha_2F_O + \alpha_3 TO_D + \alpha_4 TO_O + \alpha_5 Y_O + \alpha_6
Y_D + \epsilon\]
Summary of the significant tests of the logistic regression
model
| (Intercept) |
2.3184603 |
0.9886073 |
2.345178 |
0.0190180 |
| Tm_score |
0.2397413 |
0.0311415 |
7.698446 |
0.0000000 |
| X1stD_Off |
-0.1501170 |
0.0552602 |
-2.716547 |
0.0065967 |
| TotYd_Off |
0.0101172 |
0.0032726 |
3.091486 |
0.0019916 |
| TO_Off |
-0.8967764 |
0.1461624 |
-6.135480 |
0.0000000 |
| TotY_Def |
-0.0233840 |
0.0026075 |
-8.968079 |
0.0000000 |
| TO_Def |
0.8302725 |
0.1545586 |
5.371894 |
0.0000001 |
Predictive
Modeling
Linear
Regression
We pick our first and third linear regression models to perform
predictive modeling. First we split our data \(80:20\) between training and test sets.
From there, we perform 5-fold cross validation on our training set and
then use our test set to get final results for our chosen model.
Model 1 - Naive
| TRUE |
4.880135 |
0.7616962 |
3.809666 |
0.3319993 |
0.0162899 |
0.2574751 |
Model 2 - Total Yards
| TRUE |
6.386919 |
0.59905 |
4.998638 |
0.4116265 |
0.0376984 |
0.3158955 |
We see that model 1 performs better across all metrics and therefore
chose it to be our final model. The final results are:
RMSE R2 MAE
1 4.886772 0.7616925 3.85993
Logistic Regression
Cross Validation
We use our training data to perform 5-fold cross validation and then
use our test set to get final results for our chosen model.
Model 1 - All Features
| none |
0.8693051 |
0.7385168 |
0.0235174 |
0.0473083 |
Model 2 - Some Features
| none |
0.8715517 |
0.7430096 |
0.0409873 |
0.0822253 |
Cohen’s kappa and accuracy are high in both models. We see little
drop off in the second, simpler model and thus choose it as our final
model. We now use our entire training data to fit the model and test it
on our test data. A cufusion matrix is provided for the final model,
along with various statistics to measure model performance, with
accuracy at \(90\)%.
Confusion Matrix and Statistics
Reference
Prediction 0 1
0 44 4
1 13 47
Accuracy : 0.8426
95% CI : (0.76, 0.9055)
No Information Rate : 0.5278
P-Value [Acc > NIR] : 5.522e-12
Kappa : 0.6871
Mcnemar's Test P-Value : 0.05235
Sensitivity : 0.7719
Specificity : 0.9216
Pos Pred Value : 0.9167
Neg Pred Value : 0.7833
Prevalence : 0.5278
Detection Rate : 0.4074
Detection Prevalence : 0.4444
Balanced Accuracy : 0.8467
'Positive' Class : 0
Conclusion
Our models worked fairly well on a limited data set but could use
improvement. More data never hurts. Perhaps our models, particularly our
linear regression model, would perform better if we had data across
multiple years or if we had more features like time of possession, loss
of downs, 3rd and 4th down conversions, etc.
One thing not mentioned in the above sections is the Box-Cox
transformation. This was attempted for the linear regression but had
little effect on performance and occasionally hurt the performance.
Therefore, it was left out.
Furthermore, the expected points features were the best performers
for linear regression which is less than ideal since they are opaque
variables. It is not clear how they are calculated from other statistics
by pro-football-reference and it would be better to have the actual
statistics instead.
LS0tCnRpdGxlOiAnUmVncmVzc2lvbiBBbmFseXNpcycKYXV0aG9yOiAiIChZb3UgYXJlIGV4cGVjdGVkIHRvIGdpdmUgYSBkZXNjcmlwdGl2ZSB0aXRsZSkiCmRhdGU6ICIgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICB0b2NfZmxvYXQ6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIHNtb290aF9zY3JvbGw6IHllcwogICAgdGhlbWU6IGx1bWVuCiAgd29yZF9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBrZWVwX21kOiB5ZXMKICBwZGZfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIGZpZ193aWR0aDogMwogICAgZmlnX2hlaWdodDogMwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQogICBsaWJyYXJ5KGtuaXRyKQp9CgppZiAoIXJlcXVpcmUoImRwbHlyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQogICBsaWJyYXJ5KGRwbHlyKQp9CgppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKICAgbGlicmFyeShnZ3Bsb3QyKQp9CiAgCmlmICghcmVxdWlyZSgicGF0Y2h3b3JrIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikKICAgbGlicmFyeShwYXRjaHdvcmspCn0KCmlmICghcmVxdWlyZSgicmVzaGFwZTIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlMiIpCiAgIGxpYnJhcnkocmVzaGFwZTIpCn0KCmlmICghcmVxdWlyZSgidGlueXRleCIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoInRpbnl0ZXgiKQogICBsaWJyYXJ5KHRpbnl0ZXgpCn0KCmlmICghcmVxdWlyZSgiY2FyZXQiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJjYXJldCIpCiAgIGxpYnJhcnkoY2FyZXQpCn0KCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPUZBTFNFLCAgICAgICMgc3VwcHJlc3MgY29kZSBjaHVuawogICAgICAgICAgICAgICAgICAgICAgd2FybmluZz1GQUxTRSwgICAjIHN1cHByZXNzIHdhcm5pbmdzIAogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cz1UUlVFLCAgICMgc3VwcHJlc3Mgb3V0cHV0CiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlPUZBTFNFLCAgICMgc3VwcHJlc3MgbWVzc2FnZQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudD1OQSkKCmBgYAoKCiMgSW50cm9kdWN0aW9uCgpUaGUgTmF0aW9uYWwgRm9vdGJhbGwgTGVhZ3VlIChORkwpIGlzIGEgc3luZGljYXRlIG9mIDMyIHRlYW1zIHdoaWNoIG92ZXIgdGhlIGxhc3Qgc2V2ZXJhbCBkZWNhZGVzIGhhcyBiZWNvbWUgbm90IG9ubHkgQW1lcmljYSdzIGZhdm9yaXRlIHBhc3QgdGltZSBidXQgYWxzbyBvbmUgb2YgdGhlIG1vc3QgcHJvZml0YWJsZSBsZWFndWVzIGdsb2JhbGx5LiBJbiAyMDIzLCB0aGUgbGVhZ3VlIGdlbmVyYXRlZCBvdmVyIDIwIGJpbGxpb24gZG9sbGFycyBpbiByZXZlbnVlIGFuZCBoZWxkIDkzIHNwb3RzIGluIHRoZSB0b3AgMTAwIG1vc3Qgd2F0Y2hlZCBicm9hZGNhc3RzLiBBIGxhcmdlIHBhcnQgb2YgdGhlIHN1Y2Nlc3MgdGhlIGxlYWd1ZSBlbmpveXMgaXMgZHVlIHRvIGl0cyBzY2FyY2l0eS4gVGhlIHJlZ3VsYXIgc2Vhc29uIGlzIG9ubHkgMTggd2Vla3MgbG9uZywgd2hlcmUgZWFjaCB0ZWFtIHBsYXlzIDE3IGdhbWVzIGFsb25nIHdpdGggb25lIGJ5ZSB3ZWVrIGZvciByZXN0LiBUaGlzIGlzIGluIHNoYXJwIGNvbnRyYXN0IHRvIG90aGVyIHNwb3J0cyBsZWFndWVzIHdoZXJlIHRlYW1zIG1pZ2h0IHBsYXkgaHVuZHJlZHMgb2YgZ2FtZXMuCgpBbHRob3VnaCB0aGUgTkZMIHNlYXNvbiBpcyBzaG9ydCwgdGhlcmUgaXMgYW4gYWJ1bmRhbmNlIG9mIGRhdGEgZ2VuZXJhdGVkIGVhY2ggZ2FtZSBhbmQgb3ZlciB0aGUgc3BhbiBvZiBhIHNlYXNvbi4gRmluZGluZyB3YXlzIHRvIGxldmVyYWdlIHRoaXMgZGF0YSBpcyBpbXBvcnRhbnQgdG8gdGhlIHN1Y2Nlc3MgYW5kIGhlYWx0aCBvZiBhIHRlYW0gYW5kIGl0cyBwbGF5ZXJzLiBNb3JlIHJlY2VudGx5LCBmYW50YXN5IGxlYWd1ZXMgYW5kIHRoZSBncm93aW5nIHBvcHVsYXJpdHkgb2Ygc3BvcnRzIGdhbWJsaW5nIGhhdmUgYW1wbGlmaWVkIHRoZSBzaWduaWZpY2FuY2Ugb2YgdGhpcyBkYXRhIGZvciBmYW5zIGFuZCBXYWxsIFN0cmVldCBpbnZlc3RvcnMgc2Vla2luZyBwcm9maXRhYmxlIG9wcG9ydHVuaXRpZXMuCgpGb3IgdGhpcyBwcm9qZWN0LCB3ZSBzZWxlY3RlZCBhIHJlbGF0aXZlbHkgc2ltcGxlIGRhdGEgc2V0IGVuY29tcGFzc2luZyBib3ggc2NvcmUgc3RhdGlzdGljcyBmb3IgZWFjaCBORkwgdGVhbSBkdXJpbmcgdGhlIDIwMjMgcmVndWxhciBzZWFzb24gZ2F0aGVyZWQgZnJvbSBwcm8tZm9vdGJhbGwtcmVmZXJlbmNlIChodHRwczovL3d3dy5wcm8tZm9vdGJhbGwtcmVmZXJlbmNlLmNvbS8pLiBPdXIgZGF0YSBjb25zaXN0cyBvZiA1NDQgb2JzZXJ2YXRpb25zIGFuZCAyNSBmZWF0dXJlcyAoMjMgcHJlZGljdG9ycyBhbmQgMiByZXNwb25zZSkgd2hpY2ggYXJlIGxpc3RlZCBiZWxvdy4gT3VyIGdvYWwgaXMgc2ltcGxlOgoKMS4gQ2FuIHdlIHVzZSBib3ggc2NvcmUgc3RhdGlzdGljcyB0byBwcmVkaWN0IHRoZSBwb2ludHMgc2NvcmVkIGJ5IGEgdGVhbSB2aWEgbGluZWFyIHJlZ3Jlc3Npb24/CjIuIENhbiB3ZSB1c2UgYm94IHNjb3JlIHN0YXRpc3RpY3MgdG8gcHJlZGljdCB0aGUgcmVzdWx0IG9mIHRoZSBnYW1lIHZpYSBsb2dpc3RpYyByZWdyZXNzaW9uPwoKYFRlYW1gIDogTmFtZSBvZiB0aGUgdGVhbSBcCmBXZWVrYCA6IFdlZWsgb2YgdGhlIHNlYXNvbiBcCmBEYXlgCSA6IERheSB0aGUgZ2FtZSB3YXMgcGxheWVkIFwKYERhdGVgCSA6IERhdGUgdGhlIGdhbWUgd2FzIHBsYXllZCBcCmBUaW1lYAkgOiBUaW1lIHRoZSBnYW1lIHdhcyBwbGF5ZWQgXApgUmVzdWx0YCA6IFcgaWYgdGhlIHdvbiBvciBMIGlmIHRoZXkgbG9zdAlcCmBPVGAJICAgOiBJZiB0aGUgZ2FtZSB3ZW50IGludG8gb3ZlcnRpbWUgXApgUmVjYAkgICA6IFdpbi1sb3NzIHJlY29yZCBcCmBpc0hvbWVgIDogV2VhdGhlciB0aGUgdGVhbSBwbGF5ZWQgYXQgaG9tZSBvciBhd2F5IFwKYE9wcGAJICAgOiBPcHBvbmVudCB0aGUgdGVhbSBwbGF5ZWQgYWdhaW5zdCBcCmBUbV9zY29yZWAJOiBQb2ludHMgc2NvcmVkIFwKYE9wcF9zY29yZWAJOiBQb2ludHMgc2NvcmVkIGJ5IG9wcG9uZW50IFwKYDFzdERfT2ZmYAk6IEZpcnN0IGRvd25zIGdhaW5lZCBieSBvZmZlbnNlIFwKYFRvdFlkX09mZmAJOiBUb3RhbCB5YXJkYWdlIGdhaW5lZCBieSBvZmZlbnNlIFwKYFBhc3NZX09mZmAJOiBQYXNzaW5nIHlhcmRhZ2UgZ2FpbmVkIGJ5IG9mZmVuc2UgXApgUnVzaFlfT2ZmYAk6IFJ1c2hpbmcgeWFyZGFnZSBnYWluZWQgYnkgb2ZmZW5zZSBcCmBUT19PZmZgCSAgOiBUdXJub3ZlcnMgYnkgdGhlIG9mZmVuc2UgXApgMXN0RF9EZWZgCTogRmlyc3QgZG93bnMgZ2l2ZW4gdXAgYnkgZGVmZW5zZSBcCmBUb3RZX0RlZmAJOiBUb3RhbCB5YXJkYWdlIGdpdmVuIHVwIGJ5IGRlZmVuc2UgXApgUGFzc1lfRGVmYAk6IFBhc3NpbmcgeWFyZGFnZSBnaXZlbiB1cCBieSBkZWZlbnNlIFwKYFJ1c2hZX0RlZmAJOiBSdXNoaW5nIHlhcmRhZ2UgZ2l2ZW4gdXAgYnkgZGVmZW5zZSBcCmBUT19EZWZgCSAgOiBUdXJub3ZlcnMgY2F1c2VkIGJ5IGRlZmVuc2UgXApgT2ZmZW5zZUV4cGAJOiBFeHBlY3RlZCBwb2ludHMgYnkgb2ZmZW5zZSBcCmBEZWZlbnNlRXhwYAk6IEV4cGVjdGVkIHBvaW50cyBieSBkZWZlbnNlIFwKYFNwVG1zX0V4cGAgICA6IEV4cGVjdGVkIHBvaW50cyBieSBzcGVjaWFsIHRlYW1zIFwKIAoqTm90ZToqIFRoZSBleHBlY3RlZCBwb2ludHMgZmVhdHVyZXMgYXJlIGNhbGN1bGF0ZWQgdmlhIHBsYXkgYnkgcGxheSBkYXRhLiBBY2NvcmRpbmcgdG8gcHJvLWZvb3RiYWxsLXJlZmVyZW5jZSwgZXhwZWN0ZWQgcG9pbnRzIHJlcHJlc2VudCB0aGUgZXN0aW1hdGVkIHBvaW50IHZhbHVlIGF0IHRoZSBzdGFydCBvZiBhIGdpdmVuIHBsYXksIGJhc2VkIG9uIGRvd24sIGRpc3RhbmNlLCBhbmQgZmllbGQgcG9zaXRpb24uIAoKIyBFREEgYW5kIEZlYXR1cmUgRW5naW5lZXJpbmcKCiMjIENsZWFuaW5nIERhdGEgYW5kIEZlYXR1cmUgRW5naW5lZXJpbmcKQSBxdWljayBnbGFuY2UgYXQgb3VyIGRhdGEsIHNob3dzIHVzIHRoYXQgYWxtb3N0IGFsbCBvZiBvdXIgY29sdW1ucyBoYXZlIG1pc3NpbmcgdmFsdWVzLiBXZSBoYW5kbGUgdGhpcyBpbiB0d28gd2F5czoKCjEuIFRoZSAzMiBtaXNzaW5nIHZhbHVlcyBpbiBtYW55IG9mIG91ciBjb2x1bW5zIG9jY3VyIGJlY2F1c2UgdGhpcyBkYXRhIGluY2x1ZGVzIHRoZSBieWUgd2hlcmUgbm8gZGF0YSBpcyBnZW5lcmF0ZWQuIFdlIGRyb3AgdGhlc2Ugcm93cy4KMi4gVGhlIG90aGVyIG1pc3NpbmcgdmFsdWVzIGFyZSBkdWUgdG8gdGhlIHdheSBvdXIgc291cmNlIGlucHV0cyB0aGUgZGF0YSwgbGVhdmluZyB0aGluZ3MgYmxhbmsgd2hlbiBhbiBldmVudCBkb2VzIG5vdCBvY2N1ci4gRm9yIGV4YW1wbGUsIGluIHRoZSBPVCBjb2x1bW4sIGlmIHRoZSBnYW1lIGdvZXMgaW50byBvdmVydGltZSwgT1QgaXMgbGlzdGVkLCBvdGhlcndpc2UsIHRoZSBjZWxsIGlzIGxlZnQgYmxhbmsuIFNpbWlsYXJseSwgaWYgYSB0ZWFtIGRvZXMgbm90IGdlbmVyYXRlIGEgdHVybm92ZXIsIHRoZSBlbnRyeSBpcyBibGFuay4gV2UgZmlsbCB0aGVzZSBtaXNzaW5nIHZhbHVlcyBpbiBhcyB6ZXJvLgoKYGBge3J9CmRhdGEgPC0gcmVhZC5jc3YoJy9Vc2Vycy9oc2FsaW0vc3RhNTUxL2RhdGEudHh0JykKc3VtbWFyeShkYXRhKQpgYGAKClRvIGNsZWFuIG91ciBkYXRhLCB3ZSBzZXQgb3VyIGJpbmFyeSB2YXJpYWJsZXMgdG8gYmUgZWl0aGVyIDEgb3IgMC4gV2UgYWxzbyBjcmVhdGUsIHR3byBuZXcgYmluYXJ5IHZhcmlhYmxlcy4KCjEuIFdlIHVzZSB0aGUgYFRpbWVgIGNvbHVtbiB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIGBpc1ByaW1lVGltZWAgd2hpY2ggbGV0cyB1cyBrbm93IHdoZXRoZXIgb3Igbm90IHRoZSBnYW1lIHdhcyBwbGF5ZWQgYXQgbmlnaHQgb24gbmF0aW9uYWwgdGVsZXZpc2lvbi4KMi4gQSBgaXNUaHVyc2RheWAgZmVhdHVyZSBpcyBjcmVhdGVkIGZyb20gdGhlIGBEYXlgIGNvbHVtbiB3aGljaCBsZXRzIHVzIGtub3cgaWYgdGhlIGdhbWUgd2FzIHBsYXllZCBvbiBUaHVyc2RheS4gVGh1cnNkYXkgbmlnaHQgZ2FtZXMgYXJlIHBsYXllZCBvbiBhIHNob3J0IHdlZWsgd2hpY2ggY2FuIGxlYWQgdG8gc2xvcHB5IHBsYXkgYW5kIGluY3JlYXNlZCByaXNrIG9mIGluanVyeS4KCkFmdGVyIGRyb3BwaW5nIHVubmVjZXNzYXJ5IGNvbHVtbnMgYW5kIHJlbmFtaW5nIG90aGVyIGNvbHVtbnMsIHdlIGFyZSBsZWZ0IHdpdGggdGhlIGZvbGxvd2luZyBmZWF0dXJlczogCmBPVGAsYGF0SG9tZWAsIGBUbV9zY29yZWAJLCBgT3BwX3Njb3JlYCwgYDFzdERfT2ZmYCwgYFRvdFlkX09mZmAsIGBQYXNzWV9PZmZgLCBgUnVzaFlfT2ZmYCwgYFRPX09mZmAsIGAxc3REX0RlZmAsIGBUb3RZX0RlZmAsIGBQYXNzWV9EZWZgLCBgUnVzaFlfRGVmYCwgYFRPX0RlZmAsIGBPZmZlbnNlRXhwYCwgYERlZmVuc2VFeHBgLCBgU3BUbXNfRXhwYCwgYGlzUHJpbWVUaW1lYCwgYW5kIGBpc1RodXJzZGF5YC4KCmBgYHtyLCByZXN1bHRzPUZBTFNFfQojIFJlbW92ZSBCeWUgd2VlawpkYXRhID0gZGF0YSAlPiUgZmlsdGVyKE9wcCAhPSAnQnllIFdlZWsnKQoKIyBDaGFuZ2UgTkEgdG8gMCBpbiBUT19EZWYgYW5kIFRPX09mZgpkYXRhW2lzLm5hKGRhdGEpXSA8LSAwCgojIGZpbGwgaW4gT1QKZGF0YSRPVFtkYXRhJE9UPT0iIl0gPC0gIjAiCmRhdGEkT1RbZGF0YSRPVD09Ik9UIl0gPC0gIjEiCgojIGZpbGwgaW4gSG9tZSBTdGF0dXMKZGF0YSRhdEhvbWVbZGF0YSRhdEhvbWU9PSIiXSA8LSAiMSIKZGF0YSRhdEhvbWVbZGF0YSRhdEhvbWU9PSJAIl0gPC0gIjAiCgojVGh1cnNkYXkgZ2FtZXMKZGF0YSRpc1RodXJzZGF5IDwtIHdpdGgoZGF0YSwgaWZlbHNlKERheT09IlRodSIsIDEsIDApKQpkYXRhJGlzVGh1cnNkYXkgPC0gYXMuY2hhcmFjdGVyKGRhdGEkaXNUaHVyc2RheSkKCiNQcmltZSB0aW1lIGdhbWVzCmRhdGEkaXNQcmltZVRpbWUgPC0gd2l0aChkYXRhLCBpZmVsc2UoVGltZT09Ijc6MTVQTSBFVCIgfCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaW1lPT0iODowMFBNIEVUIiB8IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpbWU9PSI4OjE1UE0gRVQiIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaW1lPT0iODoyMFBNIEVUIiAsIDEsIDApKQpkYXRhJGlzUHJpbWVUaW1lIDwtIGFzLmNoYXJhY3RlcihkYXRhJGlzUHJpbWVUaW1lKQoKIyBDaGFuZ2UgcmVzdWx0IHRvIDEgb3IgMApkYXRhJHdpbiA8LSB3aXRoKGRhdGEsIGlmZWxzZShSZXN1bHQ9PSdXJywxLDApKQpkYXRhJHdpbiA8LSBhcy5jaGFyYWN0ZXIoZGF0YSR3aW4pCgpkYXRhIDwtIGRhdGEgJT4lIHNlbGVjdCgtYyhUZWFtLCBXZWVrLCBEYXksIERhdGUsIFRpbWUsIGJveHNjb3JlLCBSZXN1bHQsIFJlYywgT3BwX3Njb3JlLCBPcHApKQpoZWFkKGRhdGEpCmBgYAoKIyMgVmlzdWFsaXNpbmcgRGlzdHJpYnV0aW9ucwoKVGhlIGRpc3RyaWJ1dGlvbiBmb3Igb3VyIGNvbnRpbnVvdXMgbnVtZXJpY2FsIHZhcmlhYmxlcyBmb3Igb2ZmZW5zZSBhbmQgZGVmZW5zZSBhcmUgc2hvd24gYmVsb3cuIFRoZSBmaXJzdCBkb3duIHJhdGUsIHRvdGFsIHlhcmRhZ2UsIGFuZCBwYXNzaW5nIHlhcmRzIGxvb2sgdG8gYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIFRoZSBydXNoaW5nIHlhcmRzIGhhdmUgYSBzbGlnaHQgc2tldyBidXQgbm90aGluZyBtYWpvciBjYXRjaGVzIHRoZSBleWUuIFR1cm5vdmVycyBvbiB0aGUgb3RoZXIgaGFuZCBoYXZlIGEgbm90aWNlYWJsZSByaWdodCBza2V3IHdoaWNoIGlzIHRvIGJlIGV4cGVjdGVkLiAKCgpgYGB7ciwgaW5jbHVkZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kb2ZmZW5jZU1lbHQgPC0gbWVsdChkYXRhWzU6N10pCm9mZmVuY2VZYXJkYWdlIDwtIGdncGxvdChkYXRhPW9mZmVuY2VNZWx0LCBhZXMoeD12YWx1ZSwgY29sb3VyPXZhcmlhYmxlKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJZYXJkYWdlIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJPZmZlbnNpdmUgWWFyZGFnZSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZT0iVHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzPWMoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90WWRfT2ZmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQYXNzWV9PZmYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJ1c2hZX09mZiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJUb3RhbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQYXNzaW5nIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJ1c2hpbmciKSkKCmRlZmVuc2VNZWx0IDwtIG1lbHQoZGF0YVsxMDoxMl0pCmRlZmVuc2VZYXJkYWdlIDwtIGdncGxvdChkYXRhPWRlZmVuc2VNZWx0LCBhZXMoeD12YWx1ZSwgY29sb3VyPXZhcmlhYmxlKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJZYXJkYWdlIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJEZWZlbnNlIFlhcmRhZ2UiKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWU9IlR5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdFlkX0RlZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGFzc1lfRGVmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSdXNoWV9EZWYiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiVG90YWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGFzc2luZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSdXNoaW5nIikpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmZpcnN0RG93bnNPZmYgPC0gZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9WDFzdERfT2ZmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJGaXJzdCBEb3ducyIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiRmlyc3QgRG93bnMgYnkgT2ZmZW5zZSIpCgpPZmZlbnNlVE8gPC0gZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9VE9fT2ZmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9iYXIoKSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIlR1cm5vdmVycyIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiVHVybm92ZXJzIGJ5IE9mZmVuc2UiKQoKZmlyc3REb3duc0RlZiA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1YMXN0RF9EZWYpKSArIAogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2RlbnNpdHkoKSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIkZpcnN0IERvd25zIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJGaXJzdCBEb3ducyBHaXZlbiBVcCBieSBEZWZlbnNlIikKCkRlZmVuc2VUTyA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1UT19EZWYpKSArIAogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcigpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsKICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiVHVybm92ZXJzIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJUdXJub3ZlcnMiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNn0Kb2ZmZW5jZVlhcmRhZ2UgLyAoZmlyc3REb3duc09mZiArIE9mZmVuc2VUTykKYGBgCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNn0KZGVmZW5zZVlhcmRhZ2UgLyAoZmlyc3REb3duc0RlZiArIERlZmVuc2VUTykKCmBgYAoKYGBge3IsIHJlc3VsdHM9RkFMU0V9CnlhcmRhZ2VDb3IgPC0gZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9VG90WWRfT2ZmLCB5PVRvdFlfRGVmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPS41KSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NCkpICsKICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiT2ZmZW5zaXZlIFlhcmRzIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiRGVmZW5zaXZlIFlhcmRzIEdpdmVuIFVwIikKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJPIHZzIEQgWWFyZGFnZSBDb3JyZWxhdGlvbiIpCgp0dXJub3ZlckNvciA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1UT19PZmYsIHk9VE9fRGVmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPS41KSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSkpICsKICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiT2ZmZW5zaXZlIFR1cm5vdmVycyIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkRlZmVuc2l2ZSBUdXJub3ZlcnMiKQogICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIk8gdnMgRCBUdXJub3ZlciBDb3JyZWxhdGlvbiIpCiAgICAgICAgICAgICAgICAgICAgICAgIAp0b3RZdnNQYXNzQ29yIDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVBhc3NZX09mZiwgeT1Ub3RZZF9PZmYpKSArIAogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9LjUpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT01KSkgKwogICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJQYXNzIFlhcmRzIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiVG90YWwgWWFyZHMiKQogICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIk9mZmVuc2l2ZSBZYXJkYWdlIENvcnJlbGF0aW9uIikgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAKdG90WXZzUnVzaENvciA8LSBnZ3Bsb3QoZGF0YT1kYXRhLCBhZXMoeD1SdXNoWV9PZmYsIHk9VG90WWRfT2ZmKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPS41KSArIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NSkpICsKICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiUnVzaCBZYXJkcyIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIlRvdGFsIFlhcmRzIikKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJPZmZlbnNpdmUgWWFyZGFnZSBDb3JyZWxhdGlvbiIpIAogICAgICAgICAgICAgICAgICAgICAgICAKcGFzc1l2c1J1c2hDb3IgPC0gZ2dwbG90KGRhdGE9ZGF0YSwgYWVzKHg9UnVzaFlfT2ZmLCB5PVBhc3NZX09mZikpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0uNSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTUpKSArCiAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIlJ1c2ggWWFyZHMiKSArIAogICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJQYXNzIFlhcmRzIikKICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJPZmZlbnNpdmUgWWFyZGFnZSBDb3JyZWxhdGlvbiIpCmBgYAoKQ29tcGFyaW5nIHRoZSBkZWZlbnNpdmUgcGxvdHMgdnMgdGhlIG9mZmVuc2l2ZSBwbG90cyBzaG93cyB0aGF0IHRoZSBkaXN0cmlidXRpb25zIGFyZSBleGFjdGx5IHRoZSBzYW1lIGJ1dCB0aGlzIGlzIHRvIGJlIGV4cGVjdGVkLiBTaW5jZSB0d28gdGVhbXMgcGxheSBpbiBhIGdhbWUsIHdlIGhhdmUgb2JzZXJ2YXRpb25zIGZvciBib3RoIHRlYW1zIGZyb20gdGhlIHNhbWUgZ2FtZS4gRm9yIGV4YW1wbGUsIHN1cHBvc2UgdGhlIEVhZ2xlcyBwbGF5IHRoZSBHaWFudHMgYW5kIGdhaW4gNDAwIHRvdGFsIHlhcmRzLiBUaGlzIHdpbGwgc2hvdyB1cCBhcyA0MDAgdW5kZXIgYFRvdFlkX09mZmAgYnV0IHdpbGwgc2hvdyB1cCBhZ2FpbiBpbiBhbm90aGVyIG9ic2VydmF0aW9uIG9mIHRoZSBHaWFudHMgYXMgYFRvdFlfRGVmYC4gV2Ugc2VlIGluIHRoZSB0d28gcGxvdHMgYmVsb3cgdGhhdCB0aGUgb2ZmZW5zaXZlIHN0YXRzIGRvIG5vdCBjb3JyZWxhdGUgd2l0aCB0aGUgZGVmZW5zaXZlIHN0YXRzIGZvciBlYWNoIG9ic2VydmF0aW9uLgoKYGBge3IsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA1fQp5YXJkYWdlQ29yICsgdHVybm92ZXJDb3IKYGBgCgpJdCBzaG91bGQgYmUgZXhwZWN0ZWQgdGhhdCBwYXNzaW5nIGFuZCBydXNoaW5nIHlhcmRzIGFyZSBjb3JyZWxhdGVkIHdpdGggdG90YWwgeWFyZHMgd2hpY2ggaXMgaW5kZWVkIHRoZSBjYXNlLiBTdXJwcmlzaW5nbHksIHRoZXJlIGlzIGxpdHRsZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHJ1c2ggYW5kIHBhc3MgeWFyZHMuCgpgYGB7ciwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDEwfQp0b3RZdnNQYXNzQ29yICsgdG90WXZzUnVzaENvciArIHBhc3NZdnNSdXNoQ29yCmBgYAoKVG8gZnVydGhlciBjYXB0dXJlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBvdXIgbnVtZXJpY2FsIHZhcmlhYmxlcyB3ZSBjcmVhdGUgYSBQZWFyc29uIGNvcnJlbGF0aW9uIHBsb3QuIFdlIHNlZSB0aGF0IG9mZmVuc2l2ZSBleHBlY3RlZCBwb2ludHMgZmVhdHVyZSBpcyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIHlhcmRhZ2UuIFRoZSBzYW1lIGFwcGxpZXMgZm9yIGRlZmVuc2l2ZSBleHBlY3RlZCBwb2ludHMgYW5kIHlhcmRhZ2UgZ2l2ZW4gdXAuIEFuZCBvZiBjb3Vyc2UgdGhlIHRvdGFsIHlhcmRhZ2UgaXMgZGVwZW5kZW50IG9uIHJ1c2hpbmcgYW5kIHBhc3NpbmcgeWFyZGFnZS4KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOSwgZmlnLndpZHRoID0gMTB9Cm51bWVyaWNEYXRhIDwtIGRhdGFbMzoxNl0KCmNvcnJlbGF0aW9uTWF0cml4IDwtIHJvdW5kKGNvcihudW1lcmljRGF0YSwgbWV0aG9kID0gInBlYXJzb24iKSwyKSAgCgpkaXN0IDwtIGFzLmRpc3QoKDEtY29ycmVsYXRpb25NYXRyaXgpLzIpCmhjIDwtIGhjbHVzdChkaXN0KQpjb3JyZWxhdGlvbk1hdHJpeCA8LWNvcnJlbGF0aW9uTWF0cml4W2hjJG9yZGVyLCBoYyRvcmRlcl0KCmNvcnJlbGF0aW9uTWF0cml4TWVsdCA8LSBtZWx0KGNvcnJlbGF0aW9uTWF0cml4KQoKZ2dwbG90KGRhdGEgPSBjb3JyZWxhdGlvbk1hdHJpeE1lbHQsIGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD12YWx1ZSkpICsgCiAgICAgICAgZ2VvbV90aWxlKCkgKyAKICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0PTEpLAogICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICAgICAgICBnZW9tX3RleHQoYWVzKFZhcjIsIFZhcjEsIGxhYmVsID0gdmFsdWUpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA0KSArIAogICAgICAgIGxhYnModGl0bGUgPSJQZWFyc29uIENvcnJlbGF0aW9uIEhlYXRtYXAiKSArCiAgICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudDIoKQoKYGBgCgojIyBSZWxhdGlvbnNoaXAgdG8gcmVzcG9uc2UgdmFyaWFibGVzCldlIHdvdWxkIG5vdyBsaWtlIHRvIHRha2UgYSBjbG9zZXIgbG9vayBhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gb3VyIGZlYXR1cmVzIGFuZCB0aGUgcmVzcG9uc2UgdmFyaWFibGVzLlRvIGNhcHR1cmUgdGhpcyByZWxhdGlvbnNoaXAsIHdlIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdCBmb3IgZWFjaCBudW1lcmljYWwgdmFyaWFibGUgYWdhaW5zdCBvdXIgcmVzcG9uc2UgdmFyaWFibGUuIEZvciBvdXIgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB3ZSBjcmVhdGUgZGVuc2l0eSBwbG90cy4KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTIsIGZpZy53aWR0aCA9IDEwfQpzY29yZU1lbHQgPSBtZWx0KGRhdGFbMzoxNl0saWQ9J1RtX3Njb3JlJykKCmdncGxvdChzY29yZU1lbHQsIGFlcyh4ID0gdmFsdWUsIHkgPSBUbV9zY29yZSkpICsgCiAgICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsKICAgICAgICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiLCBuY29sID0gMykKCmBgYAoKYGBge3IsIHJlc3VsdHM9RkFMU0V9CnNjb3JlVnRodXJzZGF5IDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVRtX3Njb3JlLCBjb2xvdXI9aXNUaHVyc2RheSkpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2RlbnNpdHkoKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIlBvaW50cyBTY29yZWQiKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiRGVuc2l0eSIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIlBvaW50cyBzY29yZWQgb24gVGh1cnNkYXkgR2FtZXMiKSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCnNjb3JlVnByaW1lIDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVRtX3Njb3JlLCBjb2xvdXI9aXNQcmltZVRpbWUpKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJQb2ludHMgU2NvcmVkIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkRlbnNpdHkiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJQb2ludHMgc2NvcmVkIG9uIFByaW1lIFRpbWUgR2FtZXMiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgCnNjb3JlVm90IDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVRtX3Njb3JlLCBjb2xvdXI9T1QpKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJQb2ludHMgU2NvcmVkIikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkRlbnNpdHkiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJQb2ludHMgc2NvcmVkIGluIE92ZXJ0aW1lIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgIApzY29yZVZob21lIDwtIGdncGxvdChkYXRhPWRhdGEsIGFlcyh4PVRtX3Njb3JlLCBjb2xvdXI9YXRIb21lKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fZGVuc2l0eSgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiUG9pbnRzIFNjb3JlZCIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJEZW5zaXR5IikKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiUG9pbnRzIHNjb3JlZCBvbiBIb21lIHZzIEF3YXkgR2FtZXMiKQoKYGBgCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gNn0KKHNjb3JlVnRodXJzZGF5ICsgc2NvcmVWcHJpbWUpIC8gKHNjb3JlVm90ICsgc2NvcmVWaG9tZSkKYGBgCgpPYnNlcnZhdGlvbnM6CgoxLiBEZWZlbnNpdmUgc3RhdGlzdGljcyBoYXZlIG5vIGJlYXJpbmcgb24gdGhlIHBvaW50cyBzY29yZWQgd2hpY2ggaXMgbm90IHRvbyBzdXJwcmlzaW5nIHNpbmNlIGRlZmVuc2VzIHJhcmVseSBzY29yZSBwb2ludHMuCjIuIFNwZWNpYWwgdGVhbXMgZXhwZWN0ZWQgcG9pbnRzIGhhcyBubyBjb3JyZWxhdGlvbiB3aXRoIHBvaW50cyBzY29yZWQuIFRoaXMgaXMgYSBiaXQgc3VycHJpc2luZyBzaW5jZSwgZmllbGQgZ29hbHMgYW5kIGV4dHJhIHBvaW50cyBhcmUgYSBzaWduaWZpY2FudCBjaHVuayBvZiBwb2ludHMgc2NvcmVkIGR1cmluZyBhIG5vcm1hbCBnYW1lLgozLiBUdXJub3ZlcnMgbWF5IGhhdmUgYSBzbGlnaHQgY29ycmVsYXRpb24uCjQuIEEgZGlmZmVyZW5jZSBpbiB0aGUgZGlzdHJpYnV0aW9uIGJldHdlZW4gZ2FtZXMgdGhhdCB3ZW50IGludG8gb3ZlcnRpbWUgdnMgdGhvc2UgdGhhdCBkaWQgbm90LiBTaW1pbGFybHksIGhvbWUgdnMgYXdheSBnYW1lcyBoYXZlIGEgc2xpZ2h0IGRpZmZlcmVuY2UgaW4gZGlzdHJpYnV0aW9ucy4gCgpQbG90dGluZyBvdXIgZmVhdHVyZXMgYWdhaW5zdCBvdXIgc2Vjb25kIHJlc3BvbnNlIHZhcmlhYmxlLCB3ZSBzZWUgdGhhdCBhbG1vc3QgYWxsIGZlYXR1cmVzIGhhdmUgYSBkaWZmZXJlbmNlIGluIHRoZXJlIGRpc3RyaWJ0aW9ucyBmb3IgYSB3aW4gdnMgYSBsb3NzLiBUaGUgdHdvIHR1cm5vdmVyIGZlYXR1cmVzIGxvb2sgYSBiaXQgb2RkIGFuZCB0aGV5IG1heSBwb3NlIHByb2JsZW1zIGRvd25zdHJlYW0uCgpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDEwfQp3aW5NZWx0ID0gbWVsdChkYXRhW2MoMzoxMywxOSldLGlkPSd3aW4nKQoKZ2dwbG90KHdpbk1lbHQsIGFlcyh4PXZhbHVlLCBjb2xvdXI9d2luKSkgKyAKICAgICAgICBnZW9tX2RlbnNpdHkoKSArIAogICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKwogICAgICAgIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZSIpCgpgYGAKCgojIExpbmVhciBSZWdyZXNzaW9uClBvaW50cyBhcmUgcHJpbWFyaWx5IHNjb3JlZCBieSB0aGUgb2ZmZW5zZSBhbmQgYSBzbWFsbCBhbW91bnQgYnkgdGhlIHNwZWNpYWwgdGVhbXMgdmlhIGV4dHJhIHBvaW50cywgZmllbGQgZ29hbHMsIHB1bnQgYW5kIGtpY2sgcmV0dXJucy4gSW4gcmFyZSBjYXNlcywgcG9pbnRzIGNhbiBiZSBzY29yZWQgYnkgdGhlIGRlZmVuc2UuIEZvciB0aGlzIHRvIGhhcHBlbiwgYSB0dXJub3ZlciBpcyByZXF1aXJlZC4gVGhpcyBmYWN0IGhlbHBzIHVzIGNob29zZSAkfC4zfCQgYXMgdGhlIGN1dG9mZiBmb3Igc2VsZWN0aW5nIGZlYXR1cmVzIGZyb20gdGhlIGNvcnJlbGF0aW9uIHBsb3QuIFRoaXMgZGVjaXNpb24gaXMgYWxzbyBzdXBwb3J0ZWQgYnkgb3VyIHNjYXR0ZXIgcGxvdHMuCgojIyBNb2RlbCBPbmUKVGhlIGZpcnN0IG1vZGVsIHdlIGJ1aWxkIGlzIGEgbmFpdmUgbW9kZWwgdG8gc2V0IGEgYmFzZWxpbmUuIEZyb20gb3VyIHZpc3VhbGl6YXRpb24sIHdlIGtub3cgdGhhdCBvZmZlbnNpdmUgZXhwZWN0ZWQgcG9pbnRzIHdhcyB0aGUgaGlnaGVzdCBjb3JyZWxhdGVkIGZlYXR1cmUgdG8gb3VyIHJlc3BvbnNlIHZhcmlhYmxlIHNvIHdlIGNob29zZSB0aGlzIGluc3RlYWQgb2Ygb3RoZXIgb2ZmZW5zaXZlcyBzdGF0cy4gTGV0ICRPPSRgT1RgLCRIJD1gYXRIb21lYCwgJFAkPWBUbV9zY29yZWAJLCAkRl9PJD1gMXN0RF9PZmZgLCAkWV9PJCA9IGBUb3RZZF9PZmZgLCAkUF9PJCA9IGBQYXNzWV9PZmZgLCAkUl9PJCA9YFJ1c2hZX09mZmAsICRUT19PJCA9YFRPX09mZmAsICRGX0QkID1gMXN0RF9EZWZgLCAkVF9EJCA9YFRvdFlfRGVmYCwgJFBfRCQgPWBQYXNzWV9EZWZgLCAkUl9EJCA9IGBSdXNoWV9EZWZgLCAkVE9fRCQgPWBUT19EZWZgLCAkRV9PJCA9YE9mZmVuc2VFeHBgLCAkRV9EJCA9IGBEZWZlbnNlRXhwYCwgJEVfUyRgU3BUbXNfRXhwYCwgJE4kID0gYGlzUHJpbWVUaW1lYCwgYW5kICRUJCA9IGBpc1RodXJzZGF5YC4KCk91ciBmaXJzdCBtb2RlbDoKJCRNMTogXHRleHR7UG9pbnRzfSA9IFxhbHBoYV8wICsgXGFscGhhXzFFX0QrIFxhbHBoYV8yRV9PICsgXGFscGhhXzNFX1MgKyBcYWxwaGFfNEZfTyArIFxhbHBoYV81IEggKyBcYWxwaGFfNiBUT19PICsgXGFscGhhXzcgVE9fRCArIFxhbHBoYV84IE8gKyBcYWxwaGFfOSBUICsgXGFscGhhX3sxMH0gTiArIFxlcHNpbG9uJCQKCgpgYGB7ciwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDV9Cm5haXZlTW9kZWwgPSBsbShUbV9zY29yZSB+IFNwVG1zX0V4cCArIE9mZmVuc2VFeHAgKyBEZWZlbnNlRXhwICsgWDFzdERfT2ZmICsgVE9fT2ZmICsgVE9fRGVmICsgYXRIb21lICsgT1QgKyBpc1RodXJzZGF5ICsgaXNQcmltZVRpbWUsIGRhdGEgPSBkYXRhKQpwYXIobWZyb3c9YygyLDIpLCBtYXI9YygyLDMsMiwyKSkKcGxvdChuYWl2ZU1vZGVsKQpgYGAKCmBgYHtyfQprYWJsZShzdW1tYXJ5KG5haXZlTW9kZWwpJGNvZWYsIAogICAgICBjYXB0aW9uID0gIlN1bW1hcml6ZWQgc3RhdGlzdGljcyBvZiB0aGUgcmVncmVzc2lvbiBjb2VmZmljaWVudHMiKQpgYGAKCkZyb20gdGhlIG91dHB1dCBvZiBvdXIgZmlyc3QgbW9kZWwsIHdlIHNlZSB0aGF0IHBsYXlpbmcgYXQgaG9tZSBoYWQgYSBzbWFsbCBlZmZlY3Qgb24gdGhlIG91dGNvbWUuIEZ1cnRoZXJtb3JlLCB3ZSBrbm93IGZyb20gb3VyIGNvcnJlbGF0aW9uIHBsb3RzLCB0aGF0IHRoZSBkZWZlbnNpdmUgYW5kIHNwZWNpYWwgdGVhbXMgaGFkIGxpdHRsZSByZWxhdGlvbnNoaXAgdG8gb3VyIHJlc3BvbnNlIHZhcmlhYmxlLiBPdXIgc2Vjb25kIG1vZGVsIGlzIGZvY3VzZWQgb24gb2ZmZW5zaXZlIHN0YXRzIGFuZCB3ZSByZW1vdmUgdGhlIGBhdEhPTUVgIHZhcmlhYmxlLgoKIyMgTW9kZWwgMgpPdXIgc2Vjb25kIG1vZGVsOgokJE0yOiBcdGV4dHtQb2ludHN9ID0gXGFscGhhXzAgKyBcYWxwaGFfMUVfTyArICBcYWxwaGFfMkZfTyArIFxhbHBoYV8zIFRPX0QgKyBcYWxwaGFfNCBUT19PICsgXGFscGhhXzUgTyArIFxhbHBoYV82IFQgKyBcYWxwaGFfNyBOICsgXGVwc2lsb24kJAoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA1fQpvZmZNb2RlbCA9IGxtKFRtX3Njb3JlIH4gT2ZmZW5zZUV4cCArIFgxc3REX09mZiArIFRPX09mZiArIFRPX0RlZiArIGlzVGh1cnNkYXkgKyBPVCArIGlzUHJpbWVUaW1lLCBkYXRhID0gZGF0YSkgICAKcGFyKG1mcm93PWMoMiwyKSwgbWFyPWMoMiwzLDIsMikpCnBsb3Qob2ZmTW9kZWwpCmBgYAoKYGBge3J9CmthYmxlKHN1bW1hcnkob2ZmTW9kZWwpJGNvZWYsIAogICAgICBjYXB0aW9uID0gIlN1bW1hcml6ZWQgc3RhdGlzdGljcyBvZiB0aGUgcmVncmVzc2lvbiBjb2VmZmljaWVudHMiKQpgYGAKCiMjIE1vZGVsIFRocmVlClRoZSBuZXh0IHR3byBtb2RlbHMgd2UgYnVpbGQsIHdlIHJlcGxhY2Ugb2ZmZW5zaXZlIGV4cGVjdGVkIHBvaW50cyBieSB0aGUgdGhyZWUgeWFyZGFnZSBzdGF0aXN0aWNzLiBUaGUgdGhpcmQgbW9kZWwgdXNlcyBgVG90WWRfT2ZmYCBhbmQgZm91cnRoIG1vZGVsIHdpbGwgdXNlIGBSdXNoWV9PZmZgICsgYFBhc3NZX09mZmAuCgokJE0zOiBcdGV4dHtQb2ludHN9ID0gXGFscGhhXzAgKyBcYWxwaGFfMVlfTyArICBcYWxwaGFfMkZfTyArIFxhbHBoYV8zIFRPX0QgKyBcYWxwaGFfNCBUT19PICsgXGFscGhhXzUgTyArIFxhbHBoYV82IFQgKyBcYWxwaGFfNyBOICsgXGFscGhhXzggSCArIFxlcHNpbG9uJCQKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gNX0KeWFyZE1vZGVsID0gbG0oVG1fc2NvcmUgfiBUb3RZZF9PZmYgKyBYMXN0RF9PZmYgKyBUT19PZmYgKyBUT19EZWYgKyBhdEhvbWUgKyBpc1RodXJzZGF5ICsgT1QgKyBpc1ByaW1lVGltZSwgZGF0YSA9IGRhdGEpICAgCnBhcihtZnJvdz1jKDIsMiksIG1hcj1jKDIsMywyLDIpKQpwbG90KHlhcmRNb2RlbCkKYGBgCgojIyBNb2RlbCBGb3VyCkluIG91ciBmb3VydGggbW9kZWwsIHdlIHVzZSBib3RoIHJ1c2ggYW5kIHBhc3NpbmcgeWFyZHMgaW5zdGVhZCBvZiB0b3RhbCB5YXJkcy4KJCRNNDogXHRleHR7UG9pbnRzfSA9IFxhbHBoYV8wICsgXGFscGhhXzFSX08gKyBcYWxwaGFfMVBfTyArIFxhbHBoYV8zRl9PICsgXGFscGhhXzQgVE9fRCArIFxhbHBoYV81IFRPX08gKyBcYWxwaGFfNiBPICsgXGFscGhhXzcgVCArIFxhbHBoYV84IE4gKyBcYWxwaGFfOSBIICsgXGVwc2lsb24kJAoKYGBge3IsZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDV9CnRlc3QgPSBkYXRhWy1jKDQzOSw0NzkpLF0KdHlwZVlhcmRhZ2VfbW9kZWwgPSBsbShUbV9zY29yZSB+IFgxc3REX09mZiArIFJ1c2hZX09mZiArIFBhc3NZX09mZiArIFRPX09mZiArIFRPX0RlZiArIGF0SG9tZSArIGlzVGh1cnNkYXkgKyBpc1ByaW1lVGltZSArIE9ULCBkYXRhKSAgIApwYXIobWZyb3c9YygyLDIpLCBtYXI9YygyLDMsMiwyKSkKcGxvdCh0eXBlWWFyZGFnZV9tb2RlbCkKYGBgCgpgYGB7ciwgcmVzdWx0cz1GQUxTRX0Kc3VtbWFyeShuYWl2ZU1vZGVsKSRyLnNxdWFyZWQKc3VtbWFyeShvZmZNb2RlbCkkci5zcXVhcmVkCnN1bW1hcnkoeWFyZE1vZGVsKSRyLnNxdWFyZWQKc3VtbWFyeSh0eXBlWWFyZGFnZV9tb2RlbCkkci5zcXVhcmVkCmBgYApUaGUgcmVzcGVjdGl2ZSAkUl4yJCB2YWx1ZXMgZm9yIG91ciBmb3VyIG1vZGVscyBhcmU6IAoKMS4gbmFpdmVNb2RlbCA9IDAuNzcyNjg4LAoyLiBvZmZNb2RlbCA9IDAuNzMwOTg2NCwKMy4geWFyZE1vZGVsID0gMC42MTgxNTMzLAo0LiB0eXBlWWFyZGFnZV9tb2RlbCA9IDAuNjE4MzMyMgoKT3VyIG1vZGVscyBiYXNlZCBvbiBleHBlY3RlZCB2YWx1ZSBmZWF0dXJlcyBwZXJmb3JtIG11Y2ggYmV0dGVyIHRoYW4gdGhlIG9uZXMgdXNpbmcgeWFyZGFnZS4gVGhpcyBtYXkgYmUgYmVjYXVzZSB0aGUgZXhwZWN0ZWQgdmFsdWUgZmVhdHVyZXMgYXJlIGJhc2VkIG9uIG90aGVyIGluZm9ybWF0aW9uIGFuZCB0aHVzIGFyZSBtb3JlIGluZm9ybWF0aXZlLiAKCmBgYHtyfQojbGlicmFyeShNQVNTKQojYmMgPSBib3hjb3goVG1fc2NvcmUgKyAxIH4gWDFzdERfT2ZmICsgUnVzaFlfT2ZmICsgUGFzc1lfT2ZmICsgVE9fT2ZmICsgVE9fRGVmICsgYXRIb21lICsgaXNUaHVyc2RheSArIGlzUHJpbWVUaW1lLCAKIyAgICAgICBkYXRhID0gZGF0YSwgCiMgICAgICAgbGFtYmRhID0gc2VxKC0yLCAyLCBsZW5ndGggPSAyMCksIAojICAgICAgIHhsYWI9ZXhwcmVzc2lvbihwYXN0ZShsYW1iZGEpKSkKCiN0aXRsZShtYWluID0gIkJveC1Db3ggVHJhbnNmb3JtYXRpb246IDk1JSBDSSBvZiBsYW1iZGEiLCBjb2wubWFpbiA9ICJuYXZ5IiwgY2V4Lm1haW4gPSAwLjkpCgpgYGAKCiMgTG9naXN0aWMgcmVncmVzc2lvbgoKRm9yIG91ciBsb2dpc3RpYyBtb2RlbHMsIHdlIHdpbGwgb21pdCB0aGUgdGhyZWUgZXhwZWN0ZWQgcG9pbnRzIGZlYXR1cmVzIGJlY2F1c2UgdGhleSBjYXB0dXJlIHRoZSBtYXJnaW4gb2YgcG9pbnRzIGJldHdlZW4gdHdvIHRlYW1zLiBUaGUgZmlyc3QgbW9kZWwgd2UgYnVpbGQgaW5jbHVkZXMgYWxsIGZlYXR1cmVzIGFzaWRlIGZyb20gZXhwZWN0ZWQgcG9pbnRzIHNpbmNlIG91ciBleHBsb3JhdGlvbiBzaG93ZWQgYSBkaWZmZXJlbmNlIGluIGRpc3RyaWJ1dGlvbiBmb3IgZWFjaCBmZWF0dXJlLgoKIyMgTW9kZWwgT25lCkluIG91ciBmb3VydGggbW9kZWwsIHdlIHVzZSBib3RoIHJ1c2ggYW5kIHBhc3NpbmcgeWFyZHMgaW5zdGVhZCBvZiB0b3RhbCB5YXJkcy4KJCRNMTogXHRleHR7d2lufSA9IFxhbHBoYV8wICsgXGFscGhhXzFQICsgXGFscGhhXzNGX08gKyBcYWxwaGFfNCBGX0QgKyAgXGFscGhhXzUgVE9fRCArIFxhbHBoYV82IFRPX08gKyBcYWxwaGFfNyBZX08gKyBcYWxwaGFfOCBZX0QgKyBcYWxwaGFfOSBPICsgXGFscGhhX3sxMH0gVCArIFxhbHBoYV97MTF9IE4gKyBcYWxwaGFfezEyfSBIICsgXGVwc2lsb24kJAoKYGBge3J9CmRhdGEkd2luIDwtIGFzLmZhY3RvcihkYXRhJHdpbikKbG9nTW9kZWwxID0gZ2xtKHdpbiB+IFRtX3Njb3JlICsgWDFzdERfT2ZmICsgVG90WWRfT2ZmICsgVE9fT2ZmICsgWDFzdERfRGVmICsgVG90WV9EZWYgKyAgVE9fRGVmICsgYXRIb21lICsgaXNUaHVyc2RheSArIGlzUHJpbWVUaW1lICsgT1QsIGRhdGEgPSBkYXRhLCBmYW1pbHkgPSBiaW5vbWlhbCkKCm1vZGVsMV9zaWduaWZpY2FudCA9IHN1bW1hcnkobG9nTW9kZWwxKSRjb2VmCmthYmxlKG1vZGVsMV9zaWduaWZpY2FudCwgY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIHRoZSBzaWduaWZpY2FudCB0ZXN0cyBvZiAKICAgICAgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwiKQpgYGAKCkZyb20gdGhlIGFib3ZlIG91dHB1dCwgd2UgY2FuIHNlZSB0aGF0IG91ciBiaW5hcnkgdmFyaWFibGVzIGFuZCBmaXJzdCBkb3ducyBnaXZlbiB1cCBieSB0aGUgZGVmZW5zZSBoYXZlIGxpdHRsZSBpbXBhY3QgYW5kIGFyZSBub3Qgc2lnbmlmaWNhbnQuIFNvIGluIG91ciBzZWNvbmQgbW9kZWwsIHdlIHJlbW92ZSB0aGVtLgoKIyMgTW9kZWwgVHdvCgokJE0xOiBcdGV4dHt3aW59ID0gXGFscGhhXzAgKyBcYWxwaGFfMVAgKyBcYWxwaGFfMkZfTyArICBcYWxwaGFfMyBUT19EICsgXGFscGhhXzQgVE9fTyArIFxhbHBoYV81IFlfTyArIFxhbHBoYV82IFlfRCArIFxlcHNpbG9uJCQKCmBgYHtyfQpsb2dNb2RlbDIgPSBnbG0od2luIH4gVG1fc2NvcmUgKyBYMXN0RF9PZmYgKyBUb3RZZF9PZmYgKyBUT19PZmYgKyBUb3RZX0RlZiArICBUT19EZWYsIGRhdGEgPSBkYXRhLCBmYW1pbHkgPSBiaW5vbWlhbCkKCm1vZGVsMl9zaWduaWZpY2FudCA9IHN1bW1hcnkobG9nTW9kZWwyKSRjb2VmCmthYmxlKG1vZGVsMl9zaWduaWZpY2FudCwgY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIHRoZSBzaWduaWZpY2FudCB0ZXN0cyBvZiAKICAgICAgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwiKQpgYGAKCiMgUHJlZGljdGl2ZSBNb2RlbGluZyAKCiMjIExpbmVhciBSZWdyZXNzaW9uIApXZSBwaWNrIG91ciBmaXJzdCBhbmQgdGhpcmQgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzIHRvIHBlcmZvcm0gcHJlZGljdGl2ZSBtb2RlbGluZy4gRmlyc3Qgd2Ugc3BsaXQgb3VyIGRhdGEgJDgwOjIwJCBiZXR3ZWVuIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMuIEZyb20gdGhlcmUsIHdlIHBlcmZvcm0gNS1mb2xkIGNyb3NzIHZhbGlkYXRpb24gb24gb3VyIHRyYWluaW5nIHNldCBhbmQgdGhlbiB1c2Ugb3VyIHRlc3Qgc2V0IHRvIGdldCBmaW5hbCByZXN1bHRzIGZvciBvdXIgY2hvc2VuIG1vZGVsLgpgYGB7cn0KdHJhaW5JbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGRhdGEkVG1fc2NvcmUsIHA9IDAuOCwgbGlzdCA9IEZBTFNFKQp0cmFpbiA8LSBkYXRhW3RyYWluSW5kZXgsXQp0ZXN0IDwtIGRhdGFbLXRyYWluSW5kZXgsXQpgYGAKCgpgYGB7cn0KdHJhaW4uNWZvbGQgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDUpCgptb2RlbE5haXZlLjVmb2xkIDwtIHRyYWluKFRtX3Njb3JlIH4gU3BUbXNfRXhwICsgT2ZmZW5zZUV4cCArIERlZmVuc2VFeHAgKyBYMXN0RF9PZmYgKyBUT19PZmYgKyBUT19EZWYgKyBhdEhvbWUgKyBPVCArIGlzVGh1cnNkYXkgKyBpc1ByaW1lVGltZSwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLAogICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi41Zm9sZCkKCiNwcmludChtb2RlbE5haXZlLjVmb2xkKQprYWJsZShtb2RlbE5haXZlLjVmb2xkJHJlc3VsdHMsIGNhcHRpb24gPSAiTW9kZWwgMSAtIE5haXZlIikKYGBgCgpgYGB7cn0KdHJhaW4uNWZvbGQgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDUpCgptb2RlbFlhcmQuNWZvbGQgPC0gdHJhaW4oVG1fc2NvcmUgfiBUb3RZZF9PZmYgKyBYMXN0RF9PZmYgKyBUT19PZmYgKyBUT19EZWYgKyBhdEhvbWUgKyBpc1RodXJzZGF5ICsgT1QgKyBpc1ByaW1lVGltZSwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLAogICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi41Zm9sZCkKCiNwcmludChtb2RlbFlhcmQuNWZvbGQpCmthYmxlKG1vZGVsWWFyZC41Zm9sZCRyZXN1bHRzLGNhcHRpb24gPSAiTW9kZWwgMiAtIFRvdGFsIFlhcmRzIikKYGBgCgpXZSBzZWUgdGhhdCBtb2RlbCAxIHBlcmZvcm1zIGJldHRlciBhY3Jvc3MgYWxsIG1ldHJpY3MgYW5kIHRoZXJlZm9yZSBjaG9zZSBpdCB0byBiZSBvdXIgZmluYWwgbW9kZWwuIFRoZSBmaW5hbCByZXN1bHRzIGFyZToKCmBgYHtyfQpsbUZpbmFsID0gbG0oVG1fc2NvcmUgfiBTcFRtc19FeHAgKyBPZmZlbnNlRXhwICsgRGVmZW5zZUV4cCArIFgxc3REX09mZiArIFRPX09mZiArIFRPX0RlZiArIGF0SG9tZSArIE9UICsgaXNUaHVyc2RheSArIGlzUHJpbWVUaW1lLCBkYXRhID0gdHJhaW4pCmxtRmluYWxQcmVkaWN0ID0gcHJlZGljdChsbUZpbmFsLCBuZXdkYXRhID0gdGVzdCkKbG1GaW5hbE1lYW4gPSBtZWFuKChsbUZpbmFsUHJlZGljdCAtIHRlc3QkVG1fc2NvcmUpXjIpCgpkYXRhLmZyYW1lKFJNU0UgPSBSTVNFKGxtRmluYWxQcmVkaWN0LCB0ZXN0JFRtX3Njb3JlKSwKICAgICAgICAgICBSMiA9IFIyKGxtRmluYWxQcmVkaWN0LCB0ZXN0JFRtX3Njb3JlKSwKICAgICAgICAgICBNQUUgPSBNQUUobG1GaW5hbFByZWRpY3QsIHRlc3QkVG1fc2NvcmUpKQpgYGAKCiMjIExvZ2lzdGljIFJlZ3Jlc3Npb24gQ3Jvc3MgVmFsaWRhdGlvbgpXZSB1c2Ugb3VyIHRyYWluaW5nIGRhdGEgdG8gcGVyZm9ybSA1LWZvbGQgY3Jvc3MgdmFsaWRhdGlvbiBhbmQgdGhlbiB1c2Ugb3VyIHRlc3Qgc2V0IHRvIGdldCBmaW5hbCByZXN1bHRzIGZvciBvdXIgY2hvc2VuIG1vZGVsLgoKYGBge3J9CnRyYWluLjVmb2xkIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSA1KQoKbW9kZWxMb2dBbGwuNWZvbGQgPC0gdHJhaW4od2luIH4gVG1fc2NvcmUgKyBYMXN0RF9PZmYgKyBUb3RZZF9PZmYgKyBUT19PZmYgKyBYMXN0RF9EZWYgKyBUb3RZX0RlZiArICBUT19EZWYgKyBhdEhvbWUgKyBpc1RodXJzZGF5ICsgaXNQcmltZVRpbWUgKyBPVCwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiZ2xtIiwKICAgICAgICAgICAgICAgICAgICAgZmFtaWx5PWJpbm9taWFsLAogICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi41Zm9sZCkKCiNwcmludChtb2RlbExvZ0FsbC41Zm9sZCkKa2FibGUobW9kZWxMb2dBbGwuNWZvbGQkcmVzdWx0cywgY2FwdGlvbj0iTW9kZWwgMSAtIEFsbCBGZWF0dXJlcyIpCmBgYAoKYGBge3J9CnRyYWluLjVmb2xkIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSA1KQoKbW9kZWxMb2cyLjVmb2xkIDwtIHRyYWluKHdpbiB+IFRtX3Njb3JlICsgWDFzdERfT2ZmICsgVG90WWRfT2ZmICsgVE9fT2ZmICsgVG90WV9EZWYgKyAgVE9fRGVmLAogICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW4sCiAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG0iLAogICAgICAgICAgICAgICAgICAgICBmYW1pbHk9Ymlub21pYWwsCiAgICAgICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluLjVmb2xkKQoKI3ByaW50KG1vZGVsTG9nMi41Zm9sZCkKa2FibGUobW9kZWxMb2cyLjVmb2xkJHJlc3VsdHMsIGNhcHRpb249Ik1vZGVsIDIgLSBTb21lIEZlYXR1cmVzIikKYGBgCgpDb2hlbidzIGthcHBhIGFuZCBhY2N1cmFjeSBhcmUgaGlnaCBpbiBib3RoIG1vZGVscy4gV2Ugc2VlIGxpdHRsZSBkcm9wIG9mZiBpbiB0aGUgc2Vjb25kLCBzaW1wbGVyIG1vZGVsIGFuZCB0aHVzIGNob29zZSBpdCBhcyBvdXIgZmluYWwgbW9kZWwuIFdlIG5vdyB1c2Ugb3VyIGVudGlyZSB0cmFpbmluZyBkYXRhIHRvIGZpdCB0aGUgbW9kZWwgYW5kIHRlc3QgaXQgb24gb3VyIHRlc3QgZGF0YS4gIEEgY3VmdXNpb24gbWF0cml4IGlzIHByb3ZpZGVkIGZvciB0aGUgZmluYWwgbW9kZWwsIGFsb25nIHdpdGggdmFyaW91cyBzdGF0aXN0aWNzIHRvIG1lYXN1cmUgbW9kZWwgcGVyZm9ybWFuY2UsIHdpdGggYWNjdXJhY3kgYXQgJDkwJCUuICAKCmBgYHtyfQojZ2xtRmluYWwgPSBnbG0od2luIH4gVG1fc2NvcmUgKyBYMXN0RF9PZmYgKyBUb3RZZF9PZmYgKyBUT19PZmYgKyBUb3RZX0RlZiArICBUT19EZWYsIGRhdGEgPSB0cmFpbiwgZmFtaWx5ID0gYmlub21pYWwpCgpnbG1GaW5hbCA8LSB0cmFpbih3aW4gfiBUbV9zY29yZSArIFgxc3REX09mZiArIFRvdFlkX09mZiArIFRPX09mZiArIFRvdFlfRGVmICsgIFRPX0RlZiwKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLAogICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiZ2xtIiwKICAgICAgICAgICAgICAgICAgICAgZmFtaWx5PWJpbm9taWFsLCkKCmdsbUZpbmFsUHJlZGljdCA9IHByZWRpY3QoZ2xtRmluYWwsIHRlc3QpCgpjb25mdXNpb25NYXRyaXgoZGF0YT1nbG1GaW5hbFByZWRpY3QsIHRlc3Qkd2luKQpgYGAKCiMgQ29uY2x1c2lvbgpPdXIgbW9kZWxzIHdvcmtlZCBmYWlybHkgd2VsbCBvbiBhIGxpbWl0ZWQgZGF0YSBzZXQgYnV0IGNvdWxkIHVzZSBpbXByb3ZlbWVudC4gTW9yZSBkYXRhIG5ldmVyIGh1cnRzLiBQZXJoYXBzIG91ciBtb2RlbHMsIHBhcnRpY3VsYXJseSBvdXIgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwsIHdvdWxkIHBlcmZvcm0gYmV0dGVyIGlmIHdlIGhhZCBkYXRhIGFjcm9zcyBtdWx0aXBsZSB5ZWFycyBvciBpZiB3ZSBoYWQgbW9yZSBmZWF0dXJlcyBsaWtlIHRpbWUgb2YgcG9zc2Vzc2lvbiwgbG9zcyBvZiBkb3ducywgM3JkIGFuZCA0dGggZG93biBjb252ZXJzaW9ucywgZXRjLiAKCk9uZSB0aGluZyBub3QgbWVudGlvbmVkIGluIHRoZSBhYm92ZSBzZWN0aW9ucyBpcyB0aGUgQm94LUNveCB0cmFuc2Zvcm1hdGlvbi4gVGhpcyB3YXMgYXR0ZW1wdGVkIGZvciB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gYnV0IGhhZCBsaXR0bGUgZWZmZWN0IG9uIHBlcmZvcm1hbmNlIGFuZCBvY2Nhc2lvbmFsbHkgaHVydCB0aGUgcGVyZm9ybWFuY2UuIFRoZXJlZm9yZSwgaXQgd2FzIGxlZnQgb3V0LgoKRnVydGhlcm1vcmUsIHRoZSBleHBlY3RlZCBwb2ludHMgZmVhdHVyZXMgd2VyZSB0aGUgYmVzdCBwZXJmb3JtZXJzIGZvciBsaW5lYXIgcmVncmVzc2lvbiB3aGljaCBpcyBsZXNzIHRoYW4gaWRlYWwgc2luY2UgdGhleSBhcmUgb3BhcXVlIHZhcmlhYmxlcy4gSXQgaXMgbm90IGNsZWFyIGhvdyB0aGV5IGFyZSBjYWxjdWxhdGVkIGZyb20gb3RoZXIgc3RhdGlzdGljcyBieSBwcm8tZm9vdGJhbGwtcmVmZXJlbmNlIGFuZCBpdCB3b3VsZCBiZSBiZXR0ZXIgdG8gaGF2ZSB0aGUgYWN0dWFsIHN0YXRpc3RpY3MgaW5zdGVhZC4K